package com.gamefx.resource
{
	import com.gamefx.resource.events.LoaderEvent;
	
	import flash.events.Event;
	import flash.events.ProgressEvent;
	
	[Event(name="childOpen",		type="com.gamefx.resource.events.LoaderEvent")]
	[Event(name="childCancel",		type="com.gamefx.resource.events.LoaderEvent")]
	[Event(name="childComplete", 	type="com.gamefx.resource.events.LoaderEvent")]
	[Event(name="childFail", 		type="com.gamefx.resource.events.LoaderEvent")]


	public class LoaderGroup extends LoaderItem
	{
		protected var loaders:Vector.<LoaderItem>;

		public function LoaderGroup(priority:uint=1)
		{
			super(null, priority);

			_bytesTotal = _bytesLoaded = 0;

			loaders = new Vector.<LoaderItem>();
		}



		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------

		protected var _numTotal:int;

		public function get numTotal():int
		{
			return _numTotal;
		}


		protected var _numLoaded:int;

		public function get numLoaded():int
		{
			return _numLoaded;
		}






		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------



		public static function parse(queue:*):LoaderGroup
		{
			return null;
		}

		public function append(loader:LoaderItem):LoaderItem
		{
			return insert(loader, loaders.length);
		}

		public function prepend(loader:LoaderItem):LoaderItem
		{
			return insert(loader, 0);
		}

		public function insert(loader:LoaderItem, index:uint = 999999999):LoaderItem
		{
			if (loader == null)
			{
				return null;
			}

			if (index > loaders.length)
			{
				index = loaders.length;
			}

			if (loader.ownerLoader != this)
			{
				auditBytesTotal(loader.bytesTotal);
				auditNumTotal((loader is LoaderGroup) ? (loader as LoaderGroup).numTotal : 1);
			}

			remove(loader);
			loaders.splice(index, 0, loader);
			loader.ownerLoader = this;
			loader.index = index;

			if (_ownerLoader != null && status != LoaderStatus.LOADING)
			{
				_ownerLoader.insert(this, this.index);
			}

			return loader;
		}

		public function remove(loader:LoaderItem):void
		{
			if (loader.ownerLoader == null)
			{
				return;
			}

			if (loader.ownerLoader !== this)
			{
				loader.ownerLoader.remove(loader);
				return;
			}

			for (var i:int = 0; i < loaders.length; i++)
			{
				if (loaders[i] === loader)
				{
					loaders.splice(i, 1);
					return;
				}
			}

			loader.ownerLoader = null;
		}


		//--------------------------------------------------------------------------

		internal function onChildOpen(child:LoaderItem):void
		{
			dispatchEvent(new LoaderEvent(LoaderEvent.CHILD_OPEN, child));

			if (_ownerLoader != null)
			{
				_ownerLoader.onChildOpen(child);
			}
		}

		internal function onChildProgress(bytesAppend:int):void
		{
			_bytesLoaded += bytesAppend;
			dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _bytesLoaded, _bytesTotal));

			if (_ownerLoader != null)
			{
				_ownerLoader.onChildProgress(bytesAppend);
			}
		}

		internal function onChildComplete(child:LoaderItem):void
		{
			auditNumLoaded(1);
			dispatchEvent(new LoaderEvent(LoaderEvent.CHILD_COMPLETE, child));
			dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _bytesLoaded, _bytesTotal));

			if (_ownerLoader != null)
			{
				_ownerLoader.onChildComplete(child);
			}
		}

		internal function onChildCancel(child:LoaderItem):void
		{
			_bytesTotal -= (child.bytesTotal - child.bytesLoaded);
			if (child is LoaderGroup)
			{
				_numTotal += ((child as LoaderGroup).numLoaded - (child as LoaderGroup).numTotal);
			}
			else
			{
				auditNumLoaded(1);
			}
			remove(child);
			dispatchEvent(new LoaderEvent(LoaderEvent.CHILD_CANCEL, child));
			dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _bytesLoaded, _bytesTotal));

			if (_ownerLoader != null)
			{
				_ownerLoader.onChildCancel(child);
			}
		}

		internal function onChildError(child:LoaderItem):void
		{
			_bytesTotal -= (child.bytesTotal - child.bytesLoaded);
			auditNumLoaded(1);
			dispatchEvent(new LoaderEvent(LoaderEvent.CHILD_FAIL, child));
			dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _bytesLoaded, _bytesTotal));

			if (_ownerLoader != null)
			{
				_ownerLoader.onChildError(child);
			}
		}

		//--------------------------------------------------------------------------

		internal function auditNumLoaded(numAudited:int):void
		{
			_numLoaded += numAudited;

			if (_numLoaded == _numTotal)
			{
				//TODO:加载完成，派发完成事件
				dispatchEvent(new Event(Event.COMPLETE));
			}
		}

		internal function auditNumTotal(numAudited:int):void
		{
			_numTotal += numAudited;

			if (_ownerLoader != null)
			{
				_ownerLoader.auditNumTotal(numAudited);
			}
		}


		//--------------------------------------------------------------------------

		protected function shiftNextLoader():LoaderItem
		{
			var loader:LoaderItem;

			if (loaders.length > 0)
			{
				if (loaders[0] is LoaderGroup)
				{
					loader = (loaders[0] as LoaderGroup).shiftNextLoader();
					if (loader == null)
					{
						loaders.shift();
						return shiftNextLoader();
					}
				}
				else
				{
					loader = loaders.shift();
				}
			}

			if (!(this is LoaderCore))
			{
				status = LoaderStatus.PAUSED;
			}

			return loader;
		}
	}
}
